package cn.pconline.autoclub.util;

import cn.pconline.autoclub.entity.DynaInfo;
import cn.pconline.autoclub.entity.Topic;
import cn.pconline.autoclub.util.ubb.Node;
import cn.pconline.autoclub.util.ubb.UBBHandler;
import cn.pconline.autoclub.util.ubb.UBBParser;
import com.alibaba.fastjson.JSONArray;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.support.RequestContextUtils;

/**
 *
 * @author pc
 */
public class WebUtils {

    private static final Logger log = LoggerFactory.getLogger(WebUtils.class);

    public static String param(HttpServletRequest request, String name, String def) {
        String v = request.getParameter(name);
        return v == null ? def : v;
    }

    public static String paramTrim(HttpServletRequest request, String name, String def) {
        String v = request.getParameter(name);
        String s = (v == null) ? def : v;
        return s == null ? s : s.trim();
    }

    public static int paramInt(HttpServletRequest request, String name, int def) {
        String v = request.getParameter(name);
        if ((v == null) || (v.length() == 0)) {
            return def;
        }
        try {
            return Integer.parseInt(v);
        } catch (Exception ex) {
        }
        return def;
    }

    public static int paramInt(HttpServletRequest request, String name, int def, int min, int max) {
        String v = request.getParameter(name);
        if ((v == null) || (v.length() == 0)) {
            return def;
        }
        try {
            return Math.min(Math.max(paramInt(request, name, def), min), max);
        } catch (Exception ex) {
        }
        return def;
    }

    /**
     * 这个方法有点特殊，会优先获取request.getAttribute("clubId")再获取request.getParameter("clubId")
     * 自定义域名功能需要用到，详细代码见cn.pconline.autoclub.web.UrlInterceptorAdapter
     *
     * @param request
     * @param name
     * @param def
     * @return
     */
    public static long paramLong(HttpServletRequest request, String name, long def) {
        String v = "";
        if (name.equals("clubId")) {
            Object obj = request.getAttribute(name);
            if (obj != null) {
                v = obj.toString();
            }
        }
        if (StringUtils.isBlank(v)) {
            v = request.getParameter(name);
        }
        if ((v == null) || (v.length() == 0)) {
            return def;
        }
        try {
            return Long.parseLong(v);
        } catch (Exception ex) {
        }
        return def;
    }

    /**
     * 解析类似这种的字符串 id,id,id,id,id
     * @param request
     * @param name
     * @return 
     */
    public static List<Long> paramLongs(HttpServletRequest request, String name) {
        String[] idsStr = WebUtils.param(request, name, "").split(",");
        List<Long> ids = new ArrayList<Long>();
        for (String id : idsStr) {
            try {
                ids.add(Long.parseLong(id));
            } catch (NumberFormatException e) {
                continue;
            }
        }
        return ids;
    }

    public static long paramOClubId(HttpServletRequest request) {
        String v = "";
        Object obj = request.getAttribute("oClubId");
        if (obj != null) {
            v = obj.toString();
        }
        if (StringUtils.isBlank(v)) {
            v = request.getParameter("oClubId");
        }
        if (StringUtils.isBlank(v)) {
            return 0;
        }
        try {
            return Long.parseLong(v);
        } catch (NumberFormatException ex) {
        }
        return 0;
    }

    public static double paramDouble(HttpServletRequest request, String name, double def) {
        String v = request.getParameter(name);
        if ((v == null) || (v.length() == 0)) {
            return def;
        }
        try {
            return Double.parseDouble(request.getParameter(name));
        } catch (Exception ex) {
        }
        return def;
    }

    public static String cookie(HttpServletRequest request, String cookieName) {
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie c : cookies) {
                if (c.getName().equals(cookieName)) {
                    return c.getValue();
                }
            }
        }
        return null;
    }

    public static void noCache(HttpServletResponse response) {
        response.setHeader("Pragma", "No-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setHeader("Cache-Control", "no-store");
        response.setDateHeader("Expires", 0L);
    }

    public static void setCacheHeader(HttpServletResponse response, long expiresSecond) {
        setCacheHeader(response, System.currentTimeMillis(), expiresSecond);
    }

    public static void setCacheHeader(HttpServletResponse response, long lastModifiedMillis, long expiresSecond) {
        response.setHeader("Cache-Control", "max-age=" + expiresSecond);
        response.setDateHeader("Last-Modified", lastModifiedMillis);
        response.setDateHeader("Expires", lastModifiedMillis + (expiresSecond * 1000));
    }

    /**
     * 回应if-modifed-since请求，如果内容未发生更改，直接返回304给前端，
     * 不再生成后面的内容，注意此方法仅在ATS打开相关cache设置才起作用。
     *
     * @param request	请求
     * @param lastModified 当前页面业务内容的最后更新时间，譬如车友会的最后更新时间等。
     * @return true 已更改，页面应出完整内容，false 未发生更改，页面应直接返回304
     */
    public static boolean isCacheStaled(HttpServletRequest request, long lastModified) {
        long revalidate = request.getDateHeader("If-Modified-Since");
        return (revalidate == 0 || revalidate < lastModified);
    }

    /**
     * 拼接用户头像图片
     *
     * @param userId	用户ID
     * @param width	头像大小
     * @return 图片链接
     */
    public static String face(long userId, int width, long no) {
        String id = String.valueOf(userId);
        //http://i[1-5].3conline.com/images/upload/upc/face/29/52/13/6/2952136_100x100.gif
        //配置网络测试，只用i1
        //long no = userId % 5;
        //if (no == 0) {
        //	no = 5;
        //}
        //long no = 1L;
        StringBuilder sb = new StringBuilder("http://i").append(no).
                append(".3conline.com/images/upload/upc/face/");
        for (int i = 0, c = id.length(); i < c; i += 2) {
            sb.append(id.charAt(i));
            if (i < c - 1) {
                sb.append(id.charAt(i + 1));
            }
            sb.append('/');
        }
        return sb.append(id).append("_").append(width).append("x").append(width).toString();
    }

    /**
     * 拼接用户头像图片(默认为i1)
     *
     * @param userId
     * @param width
     * @return
     */
    public static String face(long userId, int width) {
        return face(userId, width, 6L);
    }

    /**
     *
     * @param carInfo
     * @return
     */
    public static String car(String carInfo) {
        if (carInfo == null) {
            return null;
        }
        String[] split = carInfo.split(";");
        if (split.length < 2) {
            return carInfo;
        } else if (split.length < 4) {
            return split[1];
        }
        return split[3];
    }

    /**
     * 车友会首页和活动列表中活动安排显示，过滤掉标签
     *
     * @param content
     * @return
     */
    public static String byteSubstring4Reply(String content) {
        return StringUtil.byteSubstring4Reply(content, 180);
    }

    /**
     * UBB转HTML代码
     *
     * @param content	UBB文本
     * @param postId	帖子ID
     * @param floor	帖子所在的楼层
     * @return	HTML文本
     */
    public static String convertUbbLazy(String content, long postId, int floor) {
        content = UBB2.ubb2html(content, postId, floor);
        return content;
    }

    /**
     * get Spring Bean
     *
     * @param <T>
     * @param request
     * @param type
     * @return
     */
    public static <T> T getBean(HttpServletRequest request, Class<T> type) {
        return RequestContextUtils.getWebApplicationContext(request).getBean(type);
    }

    /**
     * 判断请求是否是Get
     *
     * @param request
     * @return
     */
    public static boolean isGet(HttpServletRequest request) {
        return "GET".equalsIgnoreCase(request.getMethod());
    }

    /**
     * 判断请求是否是Post
     *
     * @param request
     * @return
     */
    public static boolean isPost(HttpServletRequest request) {
        return "POST".equalsIgnoreCase(request.getMethod());
    }

    /**
     *
     * @param request
     * @param name
     * @return
     */
    public static Date parseDate(HttpServletRequest request, String name) {
        return parseDate(request, name, "");
    }

    /**
     *
     * @param request
     * @param name
     * @param time
     * @return
     */
    public static Date parseDate(HttpServletRequest request, String name, String time) {
        String dateStr = param(request, name, "");
        if (StringUtils.isEmpty(dateStr)) {
            return null;
        }
        try {
            if (StringUtils.isEmpty(time)) {
                return parseDate(dateStr);
            }
            return parseDate(dateStr + " " + time);
        } catch (IllegalArgumentException e) {
            return null;
        }
    }

    public static Date parseDate(String date) {
        try {
            if (date.length() == 10) {
                return new SimpleDateFormat("yyyy-MM-dd").parse(date);
            }
            if (date.length() == 19) {
                return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(date);
            }
            if (date.length() == 16) {
                return new SimpleDateFormat("yyyy-MM-dd HH:mm").parse(date);
            }
        } catch (ParseException ex) {
            throw new IllegalArgumentException(new StringBuilder(64).append(date).append("is not an valid format for: [yyyy-MM-dd] or [yyyy-MM-dd HH:mm:ss]  or [yyyy-MM-dd HH:mm]").toString());
        }
        throw new IllegalArgumentException(new StringBuilder(64).append(date).append("is not an valid format for: [yyyy-MM-dd] or [yyyy-MM-dd HH:mm:ss] or [yyyy-MM-dd HH:mm]").toString());
    }

    /**
     * 接口 设置编码
     *
     * @param req
     * @param resp
     */
    public static void setEncoding(HttpServletRequest req, HttpServletResponse resp) {
        String queryString = req.getQueryString();
        String req_enc = getParameterBeforeSettingCharacterEncoding(queryString, "req_enc");
        String resp_enc = getParameterBeforeSettingCharacterEncoding(queryString, "resp_enc");
        if (StringUtils.isNotBlank(req_enc)) {
            try {
                req.setCharacterEncoding(req_enc);
            } catch (UnsupportedEncodingException ex) {
                log.error("setEncoding fail!", ex);
            }
        }
        if (StringUtils.isNotBlank(resp_enc)) {
            resp.setCharacterEncoding(resp_enc);
            if (resp_enc.toLowerCase().equals("gbk")) {
                resp.setContentType("text/html; charset=GBK");
            } else if (resp_enc.toLowerCase().equals("utf-8")) {
                resp.setContentType("text/html; charset=UTF-8");
            }
        } else {
//        	resp.setCharacterEncoding("GBK");
//        	resp.setContentType("text/html; charset=GBK");
            resp.setCharacterEncoding("UTF-8");
            resp.setContentType("text/html; charset=UTF-8");
        }
    }

    /**
     * 接口 设置编码,APP接口专用 设置contentType = application/json
     *
     * @param req
     * @param resp
     */
    public static void setEncoding4App(HttpServletRequest req, HttpServletResponse resp) {
        String queryString = req.getQueryString();
        String req_enc = getParameterBeforeSettingCharacterEncoding(queryString, "req_enc");
        String resp_enc = getParameterBeforeSettingCharacterEncoding(queryString, "resp_enc");
        if (StringUtils.isNotBlank(req_enc)) {
            try {
                req.setCharacterEncoding(req_enc);
            } catch (UnsupportedEncodingException ex) {
                log.error("setEncoding fail!", ex);
            }
        }
        if (StringUtils.isNotBlank(resp_enc)) {
            resp.setCharacterEncoding(resp_enc);
            if (resp_enc.toLowerCase().equals("gbk")) {
                resp.setContentType("application/json; charset=GBK");
            } else if (resp_enc.toLowerCase().equals("utf-8")) {
                resp.setContentType("application/json; charset=UTF-8");
            }
        } else {
            resp.setCharacterEncoding("UTF-8");
            resp.setContentType("application/json; charset=UTF-8");
        }
    }

    private static String getParameterBeforeSettingCharacterEncoding(String queryString, String key) {
        if (queryString == null || queryString.length() == 0) {
            return null;
        }
        int reqIdx = queryString.indexOf(key);//req_enc=utf-8&resp_enc=gbk
        if (reqIdx != -1) {
            reqIdx = reqIdx + key.length() + 1;
            int endIdx = reqIdx;
            for (;
                    endIdx < queryString.length() && queryString.charAt(endIdx) != '&';
                    endIdx++) {
            }
            if (endIdx > reqIdx) {
                return queryString.substring(reqIdx, endIdx);
            }
        }
        return null;
    }

    /**
     * md5加密，获取短信验证码防刷用到
     *
     * @param text
     * @return
     */
    public static String md5(String text) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] digest = md.digest(text.getBytes("utf-8"));
            StringBuilder buf = new StringBuilder();
            for (int i = 0; i < digest.length; i++) {
                String b = Integer.toHexString(0xFF & digest[i]);
                if (b.length() == 1) {
                    buf.append('0');
                }
                buf.append(b);
            }
            return buf.toString();
        } catch (NoSuchAlgorithmException e) {
            log.error("", e);
        } catch (UnsupportedEncodingException e) {
            log.error("", e);
        }
        return text;
    }

    /**
     * 处理省市市前面的符号
     *
     * @param request
     * @param name
     * @param def
     */
    public static String getAreaPlaceByReq(HttpServletRequest request, String name, String def) {
        String param = param(request, name, def);
        return param.replaceAll("├", "").replaceAll("└", "");
    }

    /**
     * 校验最大页码是否超出真实页码
     *
     * @param resp
     * @param pageNo
     * @param pageCount
     */
    public static void checkPageMaxNo(HttpServletResponse resp, int pageNo,
            int pageCount) {
        if (pageNo > pageCount) {
            try {
                resp.sendError(404);
            } catch (IOException ex) {
                log.error("checkPageMaxNo fail!", ex);
            }
        }
    }

    public static String transformToBBSFace(String context) {
        UBBHandler handler = new UBBHandler();
        Map<String, Node> map = new HashMap<String, Node>();
        map.put("emot", UBB2.builderMap.get("emot"));
        map.put("url", UBB2.builderMap.get("url"));
        handler.setBuilderMap(map);
        UBBParser.parse(context, handler);
        return handler.getText();
    }

    /**
     * 先调用replaceNewLine，再限制了长度，最后再去转换成表情。
     *
     * @param context
     * @param limit
     * @return
     */
    public static String transformToBBSFaceThenLimit(String context, int limit) {
        context = replaceNewLine(context);
        context = filterPicture(context);
        int len = countEmotLength(context, limit);
        String s = context;
        if (len > 0 && len < context.length()) {
            s = context.substring(0, len) + "...";
        }
        return transformToBBSFace(s);
    }
    
    /**
     * 先调用replaceNewLine，再限制了长度，最后再去转换成表情,不去除【图】。
     * @param context
     * @param limit
     * @return
     */
    public static String transformNoFilterPictureThenLimit(String context,int limit){
        context = replaceNewLine(context);
        int len = countEmotLength(context, limit);
        String s = context;
        if (len > 0 && len < context.length()) {
            s = context.substring(0, len) + "...";
        }
        return transformToBBSFace(s);
    }

    /**
     * 先调用replaceNewLine，再限制了长度，不转换成表情。
     *
     * @param context
     * @param limit
     * @return
     */
    public static String transformNoBBSFaceThenLimit(String context, int limit, int sourceAgent) {
        context = replaceNewLine(context);
        context = filterPicture(context);
        int len = countEmotLength(context, limit);
        String s = context;
        if (len > 0 && len < context.length()) {
            s = context.substring(0, len) + "...";
        }
        return EncodeUtils.encodeForHTML(s, sourceAgent);
    }

    /**
     * 先调用replaceNewLine，再限制了长度，不转换成表情,不过滤内容。
     *
     * @param context
     * @param limit
     * @return
     */
    public static String transformNoBBSFaceThenLimit(String context, int limit) {
        context = replaceNewLine(context);
        context = filterPicture(context);
        int len = countEmotLength(context, limit);
        String s = context;
        if (len > 0 && len < context.length()) {
            s = context.substring(0, len) + "...";
        }
        return s;
    }

    /**
     * 把换行符替换成成空格
     *
     * @param context
     * @return
     */
    public static String replaceNewLine(String context) {
        return context.replaceAll("\\n", " ").replaceAll("\\r", "").replaceAll("\\\\s", " ");
    }

    /**
     * 过滤[图]字
     *
     * @param context
     * @return
     */
    public static String filterPicture(String context) {
        return context.replaceAll("\\[图\\]", "");
    }
    
    /**
     * 将有正确url的内容添加url链接
     * @param content
     * @return
     */
    public static String covertLink(String content){
    	String regex = Regex.url.value;
    	Pattern pattern = Pattern.compile(regex);
    	Matcher matcher = pattern.matcher(content); 
    	StringBuffer result = new StringBuffer();
    	while (matcher.find()) { 
             StringBuffer replace = new StringBuffer(); 
             replace.append("[url=").append(matcher.group()).append("]"); 
             replace.append(matcher.group()).append("[/url]");
             matcher.appendReplacement(result, replace.toString()); 
        } 
         matcher.appendTail(result); 
         return result.toString();
    }
    

    /**
     * 替换行符后后再计算要截取的长度。一个表情[em0001]算一个字符
     *
     * @param context
     * @param limit
     * @return
     */
    public static int countEmotLength(String context, int limit) {
        char[] cs = context.toCharArray();
        int count = 0;
        for (int i = 0; i < cs.length; i++) {
            //[em0001]
            if (cs[i] == '[' && (i + 7) < cs.length && cs[i + 7] == ']') {
                i = i + 7;
            }
            count++;
            if (count == limit) {
                return i + 1;
            }
        }
        return 0;
    }

    public static String transPicUrl(String url, int width, int height) {
        if (StringUtils.isNotBlank(url)) {
            boolean isPcauto = url.matches("http://img\\.pc(online|auto)\\.com\\.cn.*");
            int index = url.lastIndexOf("_");
            int end = url.lastIndexOf(".");
            if (isPcauto) {
                if (index != -1 && end != -1 && url.lastIndexOf("/") != -1 && url.lastIndexOf(".") != -1) {
                    String subString = url.substring(url.lastIndexOf("/") + 1, url.lastIndexOf("."));
                    url = url.replaceAll("http://img.pc(online|auto).com.cn", "http://imgrt.pc$1.com.cn").replace(subString, "spcgroup/bbs/center/" + subString + "_" + width + "x" + height);
                }
            }
        }
        return url;
    }

    public static JSONArray parseArray(HttpServletRequest request, String name) {
        String js = param(request, name, "");
        try {
            return JSONArray.parseArray(js);
        } catch (com.alibaba.fastjson.JSONException e) {
            return null;
        }
    }

    public static String[] topicClass(DynaInfo dyna) {
        String[] str = new String[2];
        if (dyna.getType() == DynaInfo.TYPE_QUESTION) {
            str[0] = "提问";
            str[1] = "i-question";
        } else if (dyna.getPick() == DynaInfo.PICK_YES) {
            str[0] = "精华";
            str[1] = "a-pick1";
        } else if (dyna.getRecommend() == DynaInfo.RECOMMEND_YES) {
            str[0] = "推荐";
            str[1] = "a-pick3";
        } else if (dyna.getPostCount() > 99) {
            str[0] = "最热";
            str[1] = "a-hot";
        } else if (dyna.getIsPic() == DynaInfo.PIC_IS) {
            str[0] = "图片贴";
            str[1] = "i-pic";
        } else {
            str[0] = "普通";
            str[1] = "a-normal";
        }
        return str;
    }

    public static List<String[]> topicMark(DynaInfo dyna) {
        List<String[]> list = new ArrayList<String[]>();
        String[] str = new String[2];
        if (dyna.getPostCount() > 50) {
            str[0] = "热帖";
            str[1] = "i-hot";
            list.add(str);
        }
        Date cur = DateUtils.getNow();
        Date overdue = DateUtils.getDateAfter(dyna.getCreateDate(), 0, Topic.TYPE_NEW_TOPIC, 0, 0);
        if (cur.getTime() < overdue.getTime()) {
            str[0] = "新帖";
            str[1] = "i-new";
            list.add(str);
        }
        return list;
    }
    public static String dynaSubjectContent(String root,String content,String subjectIds){
    	Pattern p = Pattern.compile(Regex.subjectRule.value);
        Matcher matcher = p.matcher(content);
        StringBuffer sb = new StringBuffer();
        if(subjectIds==null) return content;
        String[] idsArray =subjectIds.split(",");
        int count = 0;
        try {
	        while( matcher.find() ) {
	        	if(!StringUtils.isBlank(idsArray[count])){
	        		matcher.appendReplacement( sb, "<a href='" + root + "/topic/" + idsArray[count] + ".html' target='_blank'>#"
		                + matcher.group( 1 ) + "#</a>" );
		        count++;
	        		}
	        	}
		        
        }
        catch( ArrayIndexOutOfBoundsException e ) {
        	log.warn("话题匹配错误，{},{}",content,subjectIds);
	        return content;
        }
		matcher.appendTail(sb);
        
        return sb.toString();
    }
    
    /**
     * 获取动态的话题个数
     * @param subjectIds
     * @return
     */
    public static int dynaSubjectCount(String subjectIds){
        if(StringUtils.isBlank(subjectIds))
            return 0;
        HashSet<String> set  = new HashSet<String>();
        String[] id = subjectIds.split(",");
        for(String s:id){
            set.add(s);
        }
        return set.size();
    }
}
